package edu.gatech.app4args.utils;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;

import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.TreePath;

/**
 * Handles the custom drag-and-drop behavior of CompendiumNodes from the
 * library tree to the content lists.
 *
 * @author Andrew Lunsford
 */
public class NodeDropHandler extends TransferHandler {
	/** Custom DataFlavor that only includes CompendiumNodes */
	DataFlavor nodesFlavor;
	/** An array to hold supported DataFlavors */
    DataFlavor[] flavors = new DataFlavor[1];
	/** the type of transfer action */
	int action;

	/**
	 * Creates a new NodeDropHandler with the custom DataFlavor.
	 *
	 * @param action the type of transfer action
	 */
	public NodeDropHandler(int action) {
		this.action = action;
        try {
            String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
                              ";class=\"" +
                edu.gatech.app4args.utils.CompendiumNode[].class.getName() +
                              "\"";
            nodesFlavor = new DataFlavor(mimeType);
            flavors[0] = nodesFlavor;
        } catch(ClassNotFoundException e) {
            System.out.println("ClassNotFound: " + e.getMessage());
        }
	}

	/**
	 * Determines if the drop target can import the dropped object.
	 *
	 * @param support the TransferSupport object used to determine importability
	 * @return true if the drop target can accept the dropped object
	 */
	@Override
	public boolean canImport(TransferHandler.TransferSupport support) {
		// for the demo, we'll only support drops (not clipboard paste)
		if (!support.isDrop()) {
			return false;
		}

		// only import CompendiumNodes
		if (!support.isDataFlavorSupported(nodesFlavor)) {
			return false;
		}

		boolean actionSupported = (action & support.getSourceDropActions()) == action;
		if (actionSupported) {
			support.setDropAction(action);
			return true;
		}

		return false;
	}

	/**
	 * Creates a Transferable object out of the dragged object, in this case
	 * a tree node. For this implementation it pulls the userObject from the
	 * tree node and casts it to a CompendiumNode for transfer.
	 *
	 * @param c the object that was dragged from, a Tree
	 * @return returns a transferable object that contains a CompendiumNode
	 */
	@Override
	protected Transferable createTransferable(JComponent c) {
		JTree tree = (JTree) c;
		CompendiumNode node = null;
        TreePath[] paths = tree.getSelectionPaths();
		if(paths!=null){
			node = (CompendiumNode)((CustomTreeNode)paths[0].getLastPathComponent()).getCNode();
		}

		return new CustomTransferable(node);
	}

	/**
	 * Used to get the actions supported by the drag source. In our application,
	 * we only want to support he copy of nodes from the library tree to a
	 * content list.
	 *
	 * @param c the drag source
	 * @return copy action
	 */
	@Override
    public int getSourceActions(JComponent c) {
        return COPY;
    }

	/**
	 * Handles the importation of a CompendiumNode from the library tree to the
	 * content list drop target. Calls showContext() on the target list and
	 * passes the node to it.
	 *
	 * @param support the support object for the drag-and-drop
	 * @return true if the transfer was successful
	 */
	@Override
    public boolean importData(TransferHandler.TransferSupport support) {
        if(!canImport(support)) {
            return false;
        }
        // Extract transfer data.
        CompendiumNode node = null;
        try {
            Transferable t = support.getTransferable();
            node = (CompendiumNode)t.getTransferData(nodesFlavor);
        } catch(UnsupportedFlavorException ufe) {
            System.out.println("UnsupportedFlavor: " + ufe.getMessage());
        } catch(java.io.IOException ioe) {
            System.out.println("I/O error: " + ioe.getMessage());
        }

		JList list = (JList)support.getComponent();
		((CustomListModel)list.getModel()).showContext(node, list, support.getDropLocation().getDropPoint());
        return true;
    }

	// TODO remove?
	/**
	 * Unused in current version.
	 *
	 * @param c
	 * @param data
	 * @param action
	 */
	@Override
	protected void exportDone(JComponent c, Transferable data, int action) {
		//if (action == COPY)
	}

	/**
	 * Had to be overridden, not actually used.
	 *
	 * @return the name of the class
	 */
	@Override
    public String toString() {
        return getClass().getName();
    }

	/**
	 * A custom transferable class to handle CompendiumNodes.
	 */
    public class CustomTransferable implements Transferable {
		/** The node being transfered */
		private CompendiumNode node;

		/**
		 * Creates the class with the CompendiumNode being dragged.
		 *
		 * @param node the node being transfered
		 */
        public CustomTransferable(CompendiumNode node) {
            this.node = node;
         }

		/**
		 * Checks the type of data being dragged.
		 *
		 * @param flavor the DataFlavor of the drag object
		 * @return returns the object if it is of the correct flavor
		 * @throws UnsupportedFlavorException thrown if the object is of the wrong flavor
		 */
        public Object getTransferData(DataFlavor flavor)
                                 throws UnsupportedFlavorException {
            if(!isDataFlavorSupported(flavor))
                throw new UnsupportedFlavorException(flavor);
            return node;
        }

		/**
		 * Gets the supported DataFlavors.
		 *
		 * @return the supported DataFlavors
		 */
        public DataFlavor[] getTransferDataFlavors() {
            return flavors;
        }

		/**
		 * Checks to see if a DataFlavor is supported.
		 *
		 * @param flavor the DataFlavor to check
		 * @return true if the DataFlavor is suported
		 */
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return nodesFlavor.equals(flavor);
        }
    }
}